package com.artisan.spider.backend;

import com.artisan.spider.config.SpiderConfig;
import com.artisan.spider.domain.SpScheduled;
import com.artisan.spider.service.ISpScheduledService;
import com.artisan.spider.util.SpiderUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;


@Slf4j
@Service
public class JobBackendService extends Thread {

    @Autowired
    private SpiderConfig spiderConfig;


    @Autowired
    ThreadPoolTaskScheduler threadPoolTaskScheduler;


    @Autowired
    private ISpScheduledService iSpScheduledService;

    @Autowired
    SpiderUtil spiderUtil;


    @Override
    public void run() {
        log.info("----------项目启动后自动运行-----");


        //重启将启动的任务设置为未启动
        iSpScheduledService.updateRunningStatusToWaitStartFlag();

        while (true) {
            QueryWrapper<SpScheduled> queryWrapper = new QueryWrapper<>();
            List<SpScheduled> jobs = iSpScheduledService.list(queryWrapper.lambda().eq(SpScheduled::getStartFlag, 0));
            if (CollectionUtils.isEmpty(jobs)) {
                try {
                    // log.info("JobBackendService empty job sleep 1s");
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    log.info("job backend sleep error", e);
                }
                continue;
            }
            for (final SpScheduled job : jobs) {
                log.info("job queuing uuid={}", job.getId());
                job.setStartFlag(1);
                job.setStartTime(LocalDateTime.now());
                iSpScheduledService.updateById(job);
                if (spiderConfig.isEnableLoop()) {
                    threadPoolTaskScheduler.schedule(() -> {
                                collectionInfo(job);
                            },
                            triggerContext -> {
                                // 这块每隔定时任务时间就会执行一次  所以 如果数据库的cron表达式如有改动 则在这里查询最新的cron表达式(这样就实现了 每次改完cron 而不用重启服务器)
                                String taskCron = job.getTaskCron();
                                log.info(">>>>>> 任务 [ {} ] ,实时的cron={}", job.getTaskDesc(), taskCron);
                                CronTrigger cronTrigger = new CronTrigger(taskCron);
                                return cronTrigger.nextExecutionTime(triggerContext);
                            });
                } else {
                    threadPoolTaskScheduler.execute(() -> {
                        collectionInfo(job);
                    });
                }
            }
        }

    }


    public void collectionInfo(SpScheduled sp) {
        updateJobStatusAsRunning(sp.getId());
        try (Playwright playwright = Playwright.create()) {

            Browser browser = playwright.chromium().launch();
            BrowserContext context = browser.newContext();
            Page page = context.newPage();
            page.navigate(String.format(spiderConfig.getDomain()+sp.getPageUrl(), 1));


            int pageNum;
            if(spiderConfig.isEnableFrontPage()){
                 pageNum=sp.getFrontNum();
                 sp.setPageNum(0);
            }else{
                 pageNum = Integer.valueOf(page.querySelector(".page").innerText().split("/")[1].replace("页", "").trim());
            }


            page.close();
            context.close();
            browser.close();

            QueryWrapper<SpScheduled> queryWrapper = new QueryWrapper();
            queryWrapper.eq("id", sp.getId());
            SpScheduled spScheduled = iSpScheduledService.getOne(queryWrapper);

            // 总页数-已采集的页数=剩余要采集的页数
            int shengyuNum;
            if (pageNum == 1) {
                shengyuNum = pageNum;
            } else {
                shengyuNum = pageNum - spScheduled.getPageNum();
            }
            // 计算线程数
            int threadNum = (shengyuNum - 1) / sp.getPageThread() + 1;

            // 线程运算数量
            final AtomicLong runCount = new AtomicLong(0);

            // 开启线程数
            for (int i = 0; i < threadNum; i++) {
                int finalI = i;
                threadPoolTaskScheduler.execute(() -> {
                    log.info("当前任务为-->>{},被分解为-->>{}个线程,当前线程名称为{}", sp.getTaskDesc(), threadNum, Thread.currentThread().getName());
                    try (Playwright pw = Playwright.create()) {
                        Browser bw = pw.chromium().launch();
                        int stopnum;
                        //如果不是最后一页
                        if (finalI != threadNum - 1) {
                            stopnum = (finalI + 1) * sp.getPageThread();
                        } else {
                            stopnum = pageNum;
                        }
                        for (int k = finalI * threadNum + 1; k <= stopnum; k++) {
                            spiderUtil.pageChuli(bw, sp.getColIden(), sp.getPageUrl(), k);

                            runCount.incrementAndGet();

                            spScheduled.setPageNum(spScheduled.getPageNum() + runCount.intValue());
                            iSpScheduledService.updateById(spScheduled);
                        }
                    }
                });

            }
        }
    }

    private void updateJobStatusAsRunning(String id) {
        SpScheduled spScheduled = iSpScheduledService.getById(id);
        spScheduled.setStartFlag(1);
        spScheduled.setStartTime(LocalDateTime.now());
        iSpScheduledService.updateById(spScheduled);
    }
}
